package edu.towson.cosc.cosc455.interfaces.twellener;

import edu.towson.cosc.cosc455.interfaces.SyntaxAnalyzer;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

public class mySyntaxAnalyzer implements SyntaxAnalyzer {

	private mylexicalAnalyzer lexer;
	private String thistoken;
	private ArrayList variablenames = new ArrayList();
	private ArrayList variablevalues = new ArrayList();
	PrintWriter out ;
	@Override
	public void document(mylexicalAnalyzer lexical, String outputfile ) throws CompilerException {
		// TODO Auto-generated method stub
		lexer=lexical;
		thistoken=lexer.getNextToken();
		 try {
			out = new PrintWriter(new FileWriter(outputfile));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} //checks for start document tag
		if(!thistoken.equals("#START DOCUMENT"))
		{
			String message="a start docment annotation was dexpected what a"
					+thistoken +" was found";
			
			throw new CompilerException(message);
			
		}
		//translates start tag
		out.println("<html>");
		thistoken=lexer.getNextToken();
		int defined=0;
		//checks to see if variables are defined
		if(thistoken.equals("#START DEFINE"))
		{
			
			defined=define();
		}
		//checks for the head of the document
		if(thistoken.equals("#START HEAD"))
		{
			
			head();
			
		}
		
		body();
		//checks to see that there is an end document tag
		if(!thistoken.equals("#END DOCUMENT"))
		{
			String message="an end docment annotation was expected what a"
					+thistoken +" was found";
			throw new CompilerException(message);
		}
		//gets rid of as many variables as was created
		for(int i=0;i<defined;i++)
		{
			variablenames.remove(variablenames.size()-1);
			variablevalues.remove(variablevalues.size()-1);
		}
		out.println("</html>");
		out.close();
	}

	@Override
	public void body() throws CompilerException {
		boolean validinput=false;
		while(!thistoken.equals("")&&!thistoken.equals("#END DOCUMENT"))
		{
			
			validinput=false;
			//checks for the possible tags aro plain text allowed in the body
			if(thistoken.equals("#START PARAGRAPH"))
			{
				
				paragraph();
				validinput=true;
			}
			else if(thistoken.equals("#START BOLD"))
			{
				bold();
				validinput=true;
			}
			else if(thistoken.equals("#START ITALICS"))
			{
				italics();
				validinput=true;
			}
			else if(thistoken.equals("#START LIST"))
			{
				list();
				validinput=true;
			}
					
			else if(thistoken.charAt(0)!='#')
		    {
						out.print(thistoken);
						thistoken=lexer.getNextToken();
						validinput=true;
						
					}
					else if(thistoken.equals("#NEWLINE"))
					{
						thistoken=lexer.getNextToken();
						validinput=true;
						out.println("NEWLINE TEST");
					}
					else if(thistoken.equals("#START AUDIO"))
					{
						audio();
						validinput=true;
					}
					else if(thistoken.equals("#START VIDEO"))
					{
						video();
						validinput=true;
					}
					else if(thistoken.equals("#START USE"))
					{
						use();
												validinput=true;
					}
					
				
			
			if(!validinput)
			{
				String message="non valid token was found "
						+thistoken +" was found";
				throw new CompilerException(message);
			}
			
			
		}
		

	}
	public void innerText() throws CompilerException {
		
	
	}
	public void head() throws CompilerException {
		thistoken=lexer.getNextToken();
		//translates to the head tag and checks for the title tags
		out.println("<head>");
		if(thistoken.equals("#START TITLE"))
		{
			title();
		}	
		//causes an error if there is not the end head tag
		if(!thistoken.equals("#END HEAD"))
		{
			String message="a end head annotation was dexpected what a"
					+thistoken +"was found";
			throw new CompilerException(message);
		}
		//translates the head end tag
		out.println("</head>");
		thistoken=lexer.getNextToken();
	
		

		
		

	}

	@Override
	public void title() throws CompilerException {
		thistoken=lexer.getNextToken();
		//this allows for a plain text token
		//translates the title tag and checks for plain text
		out.print("<title>");
		if(thistoken.charAt(0)!='#')
		{
			out.print(thistoken);
			thistoken=lexer.getNextToken();
		}
		//creates an error if there is not an end title tag
		if(!thistoken.equals("#END TITLE"))
		{
			String message="a start head annotation was dexpected what a"
					+thistoken +"was found";
			throw new CompilerException(message);
		}
		//translates the end title tag
		out.println("</title>");
		thistoken=lexer.getNextToken();

	}

	@Override
	public void paragraph() throws CompilerException {
		thistoken=lexer.getNextToken();
		int defined=0;
		out.print("<p>");
		//checks for variables being defined and checks how many there are
		if(thistoken.equals("#START DEFINE"))
		{
			defined=define();
		}
		boolean validinput;
		//checks for valid tags in the paragraph body
		while(!thistoken.substring(0,4).equals("#END"))
		{
			validinput=false;
			if(thistoken.equals("#START BOLD"))
			{
				bold();
				validinput=true;
			}
			else if(thistoken.equals("#START ITALICS"))
			{
				italics();
				validinput=true;
			}
			else if(thistoken.equals("#START LIST"))
			{
				list();
				validinput=true;
			}
				
			else if(thistoken.charAt(0)!='#')
					{
				        out.print(thistoken);
						thistoken=lexer.getNextToken();
						validinput=true;
					}
					else if(thistoken.equals("#NEWLINE"))
					{
						out.println("<br>");
						thistoken=lexer.getNextToken();
						validinput=true;
					}
					else if(thistoken.equals("#START AUDIO"))
					{
						
						audio();
						
						validinput=true;
					}
					else if(thistoken.equals("#START VIDEO"))
					{
						video();
						
						validinput=true;
					}
					else if(thistoken.equals("#START USE"))
					{
						use();
						
						validinput=true;
					}
					
		//if a bad tag is found it kills the program
			if(!validinput)
			{
				String message="non valid token was found "
						+thistoken +" was found";
				throw new CompilerException(message);
			}

		}
		//checks for the end of paragraph tag
		if(!thistoken.equals("#END PARAGRAPH"))
		{
			String message="a end paragraph annotation was expected what a "
					+thistoken +" was found";
			throw new CompilerException(message);
		}
		out.print("</p>");
		thistoken=lexer.getNextToken();
		//Undeclared variables that are no longer valid
		for(int i=0;i<defined;i++)
		{
			variablenames.remove(variablenames.size()-1);
			variablevalues.remove(variablevalues.size()-1);
		}
	}

	@Override
	public void bold() throws CompilerException {
		thistoken=lexer.getNextToken();
		out.print("<b>");
		int defined=0;
		//declares variables in the bold tag
		if(thistoken.equals("#START DEFINE"))
		{
			defined=define();
		}

		//checks for valid tags in the bold tag
		boolean validinput;
		while(!thistoken.equals("")&&!thistoken.equals("#END BOLD"))
		{
			validinput=false;
			if(thistoken.charAt(0)!='#')
			{
				out.print(thistoken);
				validinput=true;
				thistoken=lexer.getNextToken();
				
			}
			else if(thistoken.equals("#NEWLINE"))
			{
				validinput=true;
				out.println("newline");
				thistoken=lexer.getNextToken();
							}
			else if(thistoken.equals("#START AUDIO"))
			{
				validinput=true;
				audio();
				
							}
			else if(thistoken.equals("#START VIDEO"))
			{
				validinput=true;
				video();
				
				
			}
			else if(thistoken.equals("#START USE"))
			{
				validinput=true;
				use();
				
			}
			if(!validinput)
			{
				String message="non valid token was found "
						+thistoken +" was found";
				throw new CompilerException(message);
			}
			
		}
		if(!thistoken.equals("#END BOLD"))
		{
			String message="a end bold annotation was expected what a "
					+thistoken +" was found";
			throw new CompilerException(message);
		}
		out.print("</b>");
		thistoken=lexer.getNextToken();
		//undeclares obsolete variables 
		for(int i=0;i<defined;i++)
		{
			variablenames.remove(variablenames.size()-1-i);
			variablevalues.remove(variablevalues.size()-1-i);
		}
	}

	@Override
	public void italics() throws CompilerException {


		thistoken=lexer.getNextToken();
		out.println("<i>");
		int defined=0;
		//checks for and creates them
		if(thistoken.equals("#START DEFINE"))
		{
			defined=define();
		}

		
		boolean validinput;
		//check for valid tags in the italics 
		while(!thistoken.equals("")&&!thistoken.equals("#END ITALICS"))
		{
			validinput=false;
			if(thistoken.charAt(0)!='#')
			{
				validinput=true;
				thistoken=lexer.getNextToken();
				
			}
			else if(thistoken.equals("#NEWLINE"))
			{
				validinput=true;
				thistoken=lexer.getNextToken();
							}
			else if(thistoken.equals("#START AUDIO"))
			{
				validinput=true;
				audio();
				
							}
			else if(thistoken.equals("#START VIDEO"))
			{
				validinput=true;
				video();
				
				
			}
			else if(thistoken.equals("#START USE"))
			{
				validinput=true;
				use();
				
			}
			if(!validinput)
			{
				String message="non valid token was found "
						+thistoken +" was found";
				throw new CompilerException(message);
			}
			
		}
		if(!thistoken.equals("#END ITALICS"))
		{
			String message="a end italics annotation was expected what a "
					+thistoken +" was found";
			throw new CompilerException(message);
		}
		out.println("</i>");
		thistoken=lexer.getNextToken();
		//removes variables
		for(int i=0;i<defined;i++)
		{
			variablenames.remove(variablenames.size()-1-i);
			variablevalues.remove(variablevalues.size()-1-i);
		}

	}

	@Override
	public void list() throws CompilerException {

		out.println("");
		out.println("<ul>");
		boolean validinput;
		thistoken=lexer.getNextToken();
		//checks for valid list format
		if(!thistoken.equals("#START ITEM"))
		{

			String message="a START ITEM annotation was expected what a "
					+thistoken +" was found";
			throw new CompilerException(message);
		}
		out.print("<li>");
		thistoken=lexer.getNextToken();
		int defined=0;
			if(thistoken.equals("#START DEFINE"))
		{
			define();
		}
			//checks for valid tags inside list item
			while(!thistoken.equals("#END ITEM"))
			{
				validinput=false;
				if(thistoken.equals("#START BOLD"))
				{
					bold();
					validinput=true;
				}
				else if(thistoken.equals("#START LIST"))
				{
					list();
					validinput=true;
				}
				else if(thistoken.equals("#START ITALICS"))
				{
					italics();
					validinput=true;
				}
				else if(thistoken.equals("#START LIST"))
				{
					list();
					validinput=true;
				}
				else if(thistoken.charAt(0)!='#')
						{
							out.print(thistoken);
							thistoken=lexer.getNextToken();
							validinput=true;
						}
				else if(thistoken.equals("#NEWLINE"))
						{
							thistoken=lexer.getNextToken();
							validinput=true;
						}
				else if(thistoken.equals("#START AUDIO"))
						{
							audio();
							
							validinput=true;
						}
				else if(thistoken.equals("#START VIDEO"))
						{
							video();
							
							validinput=true;
						}
				else if(thistoken.equals("#START USE"))
						{
							use();
							
							validinput=true;
						}
						
					
			
				if(!validinput)
				{
					String message="non valid token was found "
							+thistoken +"was found";
					throw new CompilerException(message);
				}
				
			}
			out.println("</li>");
			thistoken=lexer.getNextToken();
			//checks for additional list items
		while(thistoken.equals("#START ITEM"))
		{
			out.print("<li>");
			thistoken=lexer.getNextToken();
			//checks for valid tags in the item
		while(!thistoken.equals("#END ITEM"))
		{
			validinput=false;
			if(thistoken.equals("#START BOLD"))
			{
				bold();
				validinput=true;
			}
			else if(thistoken.equals("#START LIST"))
			{
				list();
				validinput=true;
			}
			else if(thistoken.equals("#START ITALICS"))
			{
				italics();
				validinput=true;
			}
			else if(thistoken.equals("#START LIST"))
			{
				list();
				validinput=true;
			}
			else if(thistoken.charAt(0)!='#')
					{
				out.print(thistoken);
						thistoken=lexer.getNextToken();
						validinput=true;
					}
			else if(thistoken.equals("#NEWLINE"))
					{
						thistoken=lexer.getNextToken();
						validinput=true;
					}
			else if(thistoken.equals("#START AUDIO"))
					{
						audio();
						
						validinput=true;
					}
			else if(thistoken.equals("#START VIDEO"))
					{
						video();
						
						validinput=true;
					}
			else if(thistoken.equals("#START USE"))
					{
						use();
						
						validinput=true;
					}
					
				
		
			if(!validinput)
			{
				String message="non valid token was found "
						+thistoken +"was found";
				throw new CompilerException(message);
			}
			
		}thistoken=lexer.getNextToken();out.println("</li>");
		}
		
		if(!thistoken.equals("#END LIST"))
		{
			String message="end list token was expected "
					+thistoken +"was found";
			throw new CompilerException(message);
		}
		thistoken=lexer.getNextToken();
		//undeclares variables 
		for(int i=0;i<defined;i++)
		{
			variablenames.remove(variablenames.size()-1);
			variablevalues.remove(variablevalues.size()-1);
		}
		out.println("</ul>");
	}

	@Override
	public void item() throws CompilerException {
		if(thistoken.equals("#START DEFINE"))
		{
			define();
		}

	}

	@Override
	public void audio() throws CompilerException {
		thistoken=lexer.getNextToken();
		//checks for valid format of audio tag
		out.println("<audio controls>");
		out.print("<source src=\"");
		
		out.print("AUDIO START");
		if(thistoken.charAt(0)!='#')
		{
			out.print(thistoken);
			thistoken=lexer.getNextToken();
		}
		if(!thistoken.equals("#END AUDIO"))
		{
			String message="#END AUDIO tag was expected  "
					+Compiler.token +"was found";
			throw new CompilerException(message);
		}
		out.println("\">");
		thistoken=lexer.getNextToken();
		out.println("</audio>");

	}

	@Override
	public void video() throws CompilerException {
		thistoken=lexer.getNextToken();
		//check for valid format of video tags
		out.print("<source src=\"");
		if(thistoken.charAt(0)!='#')
		{
			out.print(thistoken);
			thistoken=lexer.getNextToken();
		}
		if(!thistoken.equals("#END VIDEO"))
		{
			String message="#END AUDIO tag was expected  "
					+Compiler.token +"was found";
			throw new CompilerException(message);
		}
		out.println("\">");
		thistoken=lexer.getNextToken();
	}

	@Override
	public int define() throws CompilerException {
		//creates variables in two array lists one for name one for value
		thistoken=lexer.getNextToken();
		if(!thistoken.equals("#NAME"))
		{
			String message="#NAME tag was expected  "
					+Compiler.token +"was found";
			throw new CompilerException(message);
		}
		thistoken=lexer.getNextToken();
		variablenames.add(thistoken);
		thistoken=lexer.getNextToken();
		if(!thistoken.equals("#VALUE"))
		{
			String message="#VALUE tag was expected  "
					+Compiler.token +"was found";
			throw new CompilerException(message);
		}
		
		
		thistoken=lexer.getNextToken();
		variablevalues.add(thistoken);
		thistoken=lexer.getNextToken();
		if(!thistoken.equals("#END DEFINE"))
		{
			String message="#END DEFINE tag was expected  "
					+thistoken +"was found";
			throw new CompilerException(message);
		}
		thistoken=lexer.getNextToken();
		if(thistoken.equals("#START DEFINE"))
		{
			
			return define()+1;
		}
		else{
			
			return 1;
		}
		

	}

	@Override
	public void use() throws CompilerException {
		thistoken=lexer.getNextToken();
		//checks to see if variable was created
		if(variablenames.lastIndexOf(thistoken)!=-1)
		{
			//gets the value of the variable
			out.print(variablevalues.get(variablenames.lastIndexOf(thistoken)));
		}
		else{
			String message="undeclaried varriable was called";
			throw new CompilerException(message);
		}
		thistoken=lexer.getNextToken();
		thistoken=lexer.getNextToken();
	}

}
